#ifndef __SPATIAL_H__
#define __SPATIAL_H__

#include "Bound.h"
#include "Matrix3.h"
#include "Object.h"
#include "RenderState.h"

class Node;

class Spatial : public Object
{
public:
	// local transform access
	Matrix3& rotate();
	const Matrix3& rotate() const;
	Vector3& translate();
	const Vector3& translate() const;
	Real& scale();
	const Real& scale() const;

	// world transform access
	Matrix3& world_rotate();
	const Matrix3& world_rotate() const;
	Vector3& world_translate();
	const Vector3& world_translate() const;
	Real& world_scale();
	const Real& world_scale() const;
	void set_world_transform_to_identity();

	// world bound access
	bool& world_bound();
	const Bound& world_bound() const;

	// culling
	bool& force_cull();
	const bool& force_cull() const;

	// render state
	RenderStatePtr set_render_state ( RenderState* pstate );
	RenderState*   get_render_state ( RenderState::Type type );
	RenderStatePtr remove_render_state( RenderState::Type type );
	void remove_all_states();

	// update
	void update_gs( Real app_time, bool binit = true );
	void update_rs( RenderState* previous_state[] = 0 );

	// parent access
	Node* get_parent();

protected:
	friend class BSPNode;
	friend class Node;
	friend class Renderer;
	friend class SwitchNode;

	// construction
	Spatial();
	virtual ~Spatial();

	// parent access
	void set_parent( Node* parent );

	// geometric updates
	virtual void update_world_data( Real app_time );
	virtual void update_world_bound() = 0;
	void propagate_bound_to_root();

	// render state updates
	virtual void update_render_state( RenderState* state[] ) = 0;
	void propagate_state_from_root( RenderState* state[] );

	// drawing
	void on_draw( Renderer& renderer );
	virtual void draw( Renderer& renderer ) = 0;

	// parent
	Node* m_parent;

	// local transform
	Matrix3& m_rotate;
	Vector3 m_translate;
	Real m_scale;

	// world transforms
	Matrix3 m_world_rotate;
	Vector3 m_world_translate;
	Real m_world_scale;

	// world bound
	Bound m_world_bound;

	// culling
	bool m_force_cull;

	// render state
	RenderState::List* m_state_list;
};

#include "Spatial.inl"

#endif


	